package com.wlyuan.open.application.service;

import com.wlyuan.core.domain.Identifier;
import com.wlyuan.core.domain.valueobj.UserId;
import com.wlyuan.core.exception.ValueError;
import com.wlyuan.mybatis.query.PageUtils;
import com.wlyuan.open.api.IOpenApiCompanyService;
import com.wlyuan.open.application.translator.OpenApiCompanyTranslator;
import com.wlyuan.open.application.translator.OpenApiInfoTranslator;
import com.wlyuan.open.domain.api.OpenApi;
import com.wlyuan.open.domain.api.OpenApiInfo;
import com.wlyuan.open.domain.api.OpenApiPattern;
import com.wlyuan.open.domain.api.respository.OpenApiInfoRepository;
import com.wlyuan.open.domain.api.respository.OpenApiRepository;
import com.wlyuan.open.domain.api.service.OpenApiInfoService;
import com.wlyuan.open.domain.api.service.OpenApiService;
import com.wlyuan.open.domain.api.valueobj.OpenApiId;
import com.wlyuan.open.domain.api.valueobj.OpenApiInfoId;
import com.wlyuan.open.domain.client.OpenClient;
import com.wlyuan.open.domain.client.OpenClientId;
import com.wlyuan.open.domain.client.OpenClientPattern;
import com.wlyuan.open.domain.client.respository.OpenClientApiCacheRepository;
import com.wlyuan.open.domain.client.respository.OpenClientRepository;
import com.wlyuan.open.dto.api.*;
import com.wlyuan.open.vo.OpenApiCompanyDetailVO;
import com.wlyuan.open.vo.OpenApiCompanyVO;
import com.wlyuan.utils.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.var;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.util.CollectionUtils;

import java.util.Collections;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author lijing
 */
@DubboService
@Slf4j
@RequiredArgsConstructor
public class OpenApiCompanyServiceImpl implements IOpenApiCompanyService {
    private final OpenClientRepository openClientRepository;
    private final OpenApiRepository openApiRepository;
    private final OpenApiInfoRepository openApiInfoRepository;
    private final OpenApiService openApiService;
    private final OpenClientApiCacheRepository openClientApiCacheRepository;
    private final OpenApiInfoService openApiInfoService;

    @Override
    public void create(OpenApiCompanyCreationDTO creation) {
        var openClient = openClientRepository.ofAppId(creation.getAppId());
        if (openClient == null || StringUtils.isBlank(openClient.getAppId())) {
            throw new ValueError("开放账号不存在");
        }
        var clientId = openClient.getId();
        var apiId = new OpenApiId(creation.getApiId());
        var api = openApiRepository.ofId(apiId);
        if (api == null || !api.hasEnable()) {
            throw new ValueError("申请接口不存在");
        }
        //拒绝后重复申请
        var openApi = openApiInfoRepository.getByClientIdAndApiId(clientId, apiId);
        //存在，并且有效 或者 禁用，不能重复申请
        if (openApi != null && openApi.hasExists()) {
            logger.warn("申请接口信息:{}", openApi);
            throw new ValueError("请勿重复申请");
        }
        if (openApi == null) {
            openApi = OpenApiInfoTranslator.translate(clientId.getId(), apiId.getId());
        }
        //拒绝后重复申请，重置状态和原因 , 次数
        openApi.save(new UserId(creation.getUserId()), openApi.getTotalNum(), openApi.getLeaveNum());
        openApiInfoRepository.save(openApi);
        openClientApiCacheRepository.remove(clientId);
    }

    /**
     * 管理中台 - 获取申请接口列表
     *
     * @param filter
     * @return
     */
    @Override
    public Page<OpenApiCompanyDetailVO> search(OpenApiCompanyFilterDTO filter) {
        //需要将clientName转成 clientId；apiName转成apiId
        var clientMap = clientMap(filter);
        if (CollectionUtils.isEmpty(clientMap)) {
            return new Page<>(filter.getPage(), filter.getSize(), Collections.emptyList(), 0L);
        }
        var apiMap = apiMap(filter);
        if (CollectionUtils.isEmpty(apiMap)) {
            return new Page<>(filter.getPage(), filter.getSize(), Collections.emptyList(), 0L);
        }
        var result = openApiInfoRepository.search(filter);
        var list = openApiInfoRepository.list(result.getRecords());
        return PageUtils.as(result, OpenApiInfoTranslator.translate(list, clientMap, apiMap));
    }

    private Map<OpenClientId, OpenClient> clientMap(OpenApiCompanyFilterDTO filter) {
        //有应用名称查询条件，并且查到的数据就返回查到的应用数据，否则返回所有的应用数据
        if (StringUtils.isNotBlank(filter.getClientName())) {
            var clients = openClientRepository.ofPatternName(new OpenClientPattern("", filter.getClientName()));
            //没有查到相应的应用名称，则查询列表为空
            if (CollectionUtils.isEmpty(clients)) {
                return Collections.emptyMap();
            }
            filter.setClientName("");
            filter.setClientId(clients.stream().map(OpenClient::getId).map(Identifier::getId).collect(Collectors.toList()));
            return openClientRepository.ofAll().stream().collect(Collectors.toMap(OpenClient::getId, client -> client));
        }
        filter.setClientName("");
        return openClientRepository.ofAll().stream().collect(Collectors.toMap(OpenClient::getId, client -> client));
    }

    private Map<OpenApiId, OpenApi> apiMap(OpenApiCompanyFilterDTO filter) {
        //有接口名称查询条件，并且查到的数据就返回查到的接口数据，否则返回所有的接口数据
        if (StringUtils.isNotBlank(filter.getApiName())) {
            var apis = openApiRepository.ofPattern(new OpenApiPattern(filter.getApiName()));
            //没有查到相应的接口名称，则查询列表为空
            if (CollectionUtils.isEmpty(apis)) {
                return Collections.emptyMap();
            }
            filter.setApiId(apis.stream().map(OpenApi::getId).map(Identifier::getId).collect(Collectors.toList()));
            filter.setApiName("");
            return apis.stream().collect(Collectors.toMap(OpenApi::getId, api -> api));
        }
        filter.setApiName("");
        return openApiRepository.ofAll().stream().collect(Collectors.toMap(OpenApi::getId, api -> api));
    }

    @Override
    public Page<OpenApiCompanyVO> list(OpenApiCompanyDTO filter) {
        var client = openClientRepository.ofAppId(filter.getAppId());
        if (client == null) {
            throw new ValueError("开放账号不存在");
        }
        //获取所有有效的api接口列表
        resolverFilter(filter);
        var apiPage = openApiService.getAllInvalidPageApi(filter);
        if (apiPage == null) {
            return Page.builder().build().empty(filter);
        }
        var openClientId = client.getId();
        //获取客户端申请的
        var list = openApiInfoRepository.getByClientId(openClientId);
        //获取申请状态
        var map = list.stream().collect(Collectors.toMap(OpenApiInfo::getApiId, Function.identity()));
        return PageUtils.as(apiPage, OpenApiCompanyTranslator.translate(apiPage.getRecords(), map));
    }

    private void resolverFilter(OpenApiCompanyDTO filter) {
        filter.setAppId("");
        filter.setClientId(null);
    }

    @Override
    public void examine(OpenApiCompanyExamineDTO examineDTO) {
        var apply = openApiInfoRepository.ofId(new OpenApiInfoId(examineDTO.getApplyId()));
        if (apply == null) {
            throw new ValueError("申请记录不存在");
        }

        var api = openApiRepository.ofId(new OpenApiId(apply.getApiId()));
        if (api == null) {
            throw new ValueError("接口不存在");
        }
        if (!api.hasEnable()) {
            throw new ValueError("该接口已被禁用");
        }
        apply.examine(examineDTO.getUser());
        openApiInfoRepository.save(apply);
        openClientApiCacheRepository.remove(new OpenClientId(apply.getClientId()));
    }

    @Override
    public void reject(OpenApiCompanyRejectDTO rejectDTO) {
        var apply = openApiInfoRepository.ofId(new OpenApiInfoId(rejectDTO.getApplyId()));
        if (apply == null) {
            throw new ValueError("申请记录不存在");
        }
        var api = openApiRepository.ofId(new OpenApiId(apply.getApiId()));
        if (api == null) {
            throw new ValueError("接口不存在");
        }
        if (!api.hasEnable()) {
            throw new ValueError("该接口已被禁用");
        }
        apply.reject(rejectDTO.getUser(), rejectDTO.getReason());
        openApiInfoRepository.save(apply);
        openClientApiCacheRepository.remove(new OpenClientId(apply.getClientId()));
    }

    @Override
    public void enable(OpenApiCompanyEnableDTO enableDTO) {
        var apply = openApiInfoRepository.ofId(new OpenApiInfoId(enableDTO.getApplyId()));
        if (apply == null) {
            throw new ValueError("申请记录不存在");
        }
        var api = openApiRepository.ofId(new OpenApiId(apply.getApiId()));
        if (api == null) {
            throw new ValueError("接口不存在");
        }
        if (!api.hasEnable()) {
            throw new ValueError("该接口已被禁用");
        }
        apply.enable(enableDTO.getUser());
        openApiInfoRepository.save(apply);
        openClientApiCacheRepository.remove(new OpenClientId(apply.getClientId()));
    }

    @Override
    public void disable(OpenApiCompanyDisableDTO disableDTO) {
        var apply = openApiInfoRepository.ofId(new OpenApiInfoId(disableDTO.getApplyId()));
        if (apply == null) {
            throw new ValueError("申请记录不存在");
        }
        var api = openApiRepository.ofId(new OpenApiId(apply.getApiId()));
        if (api == null) {
            throw new ValueError("接口不存在");
        }
        if (!api.hasEnable()) {
            throw new ValueError("该接口已被禁用");
        }
        apply.disable(disableDTO.getUser());
        openApiInfoRepository.save(apply);
        openClientApiCacheRepository.remove(new OpenClientId(apply.getClientId()));
    }

    @Override
    public OpenApiCompanyDetailVO getOpenApiInfo(String appId, Long apiId) {
        return OpenApiInfoTranslator.translate(openApiInfoService.getOpenApiInfo(appId, apiId));
    }

    @Override
    public void apiCall(OpenApiCompanyDetailVO openApiInfoVO) {
        //openApiInfoService.apiCall(openApiInfoVO);
    }
}
